﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Crank.Core
{
    public class ModelBuildingParser : ParserBase
    {
        private DataModel model;

        private IList<EntityDef> previous;
        private IList<EntityDef> current;
        private IList<AttributeDef> attributes;
        private string currentLinkType;
        private AttributeDef currentLinkAttribute;

        private bool AfterLink = false;

        #region Blackboard Properties

        private static IProperty<bool> DefaultOptionality = Blackboard.Create<bool>("DefaultOptionality");

        #endregion

        public ModelBuildingParser(DataModel model)
        {
            this.model = model;
        }

        private void Reset()
        {
            AfterLink = false;
            current = new List<EntityDef>();
            previous = null;
            attributes = new List<AttributeDef>();
            currentLinkType = String.Empty;
            currentLinkAttribute = new AttributeDef();
        }

        private void ResolveLinks()
        {
            if (previous != null)
            {
                foreach (EntityDef lhs in previous)
                {
                    foreach (EntityDef rhs in current)
                    {
                        LinkDef newLink = new LinkDef(currentLinkType);
                        newLink.LHS = lhs;
                        newLink.RHS = rhs;
                        newLink.Detail = currentLinkAttribute;
                        model.Links.Add(newLink);
                    }
                }
                currentLinkAttribute = new AttributeDef();
            }
        }

        protected override void StartExpression()
        {
            if (AfterLink)
            {
                AfterLink = false;
                return;
            }
            ResolveLinks();
            Reset();
        }

        protected override void MentionEntity(string entity)
        {
            current.Add(model.GetEntityByName(entity));
        }

        protected override void MentionAttribute(string attribute, bool? isRequired, bool isKey, bool isAuto)
        {
            AttributeDef newAttribute = new AttributeDef(attribute);
            newAttribute.IsRequired = isRequired.HasValue ? isRequired.Value : DefaultOptionality.Value;
            newAttribute.IsKey = isKey;
            newAttribute.IsAuto = isAuto;
            if (AfterLink)
            {
                currentLinkAttribute = newAttribute;
            }
            else
            {
                attributes.Add(newAttribute);
            }
        }

        protected override void MentionAttributeType(string type)
        {
            foreach (var attribute in attributes)
            {
                attribute.Type = type;
                foreach (var entity in current)
                {
                    entity.Attributes.Add(attribute);
                }
            }
            attributes = new List<AttributeDef>();
        }

        protected override void MentionLink(string type)
        {
            ResolveLinks();
            previous = current;
            current = new List<EntityDef>();
            currentLinkType = type;
            AfterLink = true;
        }

        protected override void Finished()
        {
            ResolveLinks();
        }
    }

    public static class ModelBuildingParserDataModelExtensions
    {
        public static void Parse(this DataModel model, ITokenProvider tokens)
        {
            var parser = new ModelBuildingParser(model);
            parser.Parse(tokens);
        }
    }
}
